// ==UserScript==
// @name         Todo List
// @namespace    private
// @version      0.3.5
// @description  Add todo list to every pages you visit! See bottom right corner for the todo list!
// @author       lantian_bupt@163.com
// @require      https://ajax.proxy.ustclug.org/ajax/libs/jquery/1.12.4/jquery.min.js
// @require      https://cdn.bootcss.com/vue/2.2.2/vue.min.js
// @include      http*://*
// @grant        GM_getValue
// @grant        GM_setValue
// @updateURL    https://gitee.com/lt123345/todo-list/raw/master/todo-list.user.js
// ==/UserScript==

(function() {
    'use strict';

    // Do not add my todo list in iframe
    if (window.frames.length != parent.frames.length) {
        return;
    }

    // Read todo list data from locale storage
    var todoList = GM_getValue('todoList') || []; //Format: [{name:"todo item 1", done: true}, {name:"todo item 2", done: false}]
    var todoListVersion = GM_getValue('todoList.version') || 0; //Timestamp for the todo list
    //console.table(todoList);

    // Add self-defined css styles here
    $(document.head).append(`
<style>
#todoListView, #todoListView * { font-size: 12px; font-family: arial; font-weight: normal; color: white; box-sizing: unset; }
#todoListView { position: fixed; right: 10px; bottom: 10px; z-index: 9999; background-color: rgba(0, 0, 0, 0.65); padding: 10px; height: 20px; line-height: 20px; border-radius: 5px; }
#todoListView:hover { border-radius: 0 0 5px 5px; }
#todoListView .todo-badge { border-radius: 10px; padding: 2px 4px; background-color: #a33; }
#todoListView .todo-badge.todo-badge-green { background-color: #3a3; }
#todoListView .todo-list { visibility: hidden; opacity: 0; position: fixed; bottom: 50px; right: 10px; background-color: rgba(0,0,0,0.65); padding: 5px; transition: opacity 200ms, visibility 200ms; border-radius: 5px 5px 0 5px; }
#todoListView:hover .todo-list { visibility: visible; opacity: 1; transition: 500ms; }
#todoListView .todo-list ul { padding: 0; margin: 0; list-style: none; }
#todoListView .todo-list ul li label { cursor: pointer; margin: 0; margin-right: 2em; text-transform: none; font-weight: normal; line-height: 26px; width: auto; }
#todoListView .todo-list ul li { padding: 5px; margin: 0; border-bottom: 1px solid #999; text-align: left; height: 36px; line-height: 26px; box-sizing: border-box; list-style: none; transition: 300ms; }
#todoListView .todo-list ul li:last-child { border-bottom: none; }
#todoListView .todo-list ul li .todo-title { margin-right: 0.5em; }
#todoListView .todo-list ul li input { border: 1px solid #aaa; border-radius: 3px; padding: 3px; background: none; color: white; height: 15px; vertical-align: middle; margin: 0; display: inline; }
#todoListView .todo-list ul li input[type=checkbox] { width: auto; }
#todoListView .todo-list ul li:hover { background-color: rgba(255, 255, 255, 0.1); }
#todoListView .todo-list ul li.todo-title * { font-weight: bold; }
#todoListView .todo-button { border-radius: 2px; background-color: #3bd; color: white; border: none; font-size: 12px; line-height: 15px; height: 15px; width: 15px; margin-top: 5px; text-align: center; cursor: pointer; }
#todoListView .todo-button.todo-checkbox { border-radius: 1em; display: inline-block; background: none; border: 1px solid #ddd; transition: 400ms; }
#todoListView .todo-button.todo-checkbox.todo-checked { background-color: #3bd; border-color: #3bd; }
#todoListView .todo-button.todo-checkbox.todo-checked:before { content: '✔︎'; position: relative; top: 1px; left: 2px; }
#todoListView .float-right { float: right; }
#todoListView .float-left { float: left; }
#todoListView .clearfix:after { content: '.'; visibility: hidden; clear: both; }
#todoListView .clearfix:before { display: none; }
#todoListView .todo-editing { width: calc(100% - 2.5em); }
#todoListView .margin-right-5 { margin-right: 5px; }
</style>`);

    // This is the todo list view definition
    $(document.body).append(`
<div id="todoListView">
 <span>Todos </span>
 <span class="todo-badge todo-badge-green">{{doneTodoCount}}</span>
 <span class="todo-badge">{{unDoneTodoCount}}</span>
 <div class="todo-list">
  <ul>
   <li class="todo-title" class="clearfix">
    <span class="todo-badge todo-badge-green">{{doneTodoCount}}</span> Done &nbsp;&nbsp;
    <span class="todo-badge">{{unDoneTodoCount}}</span> Left
   </li>
   <li v-for="i in sortedIndexes" class="clearfix">
    <div class="float-left">
     <span :class="['todo-button', 'todo-checkbox', todoList[i].done && 'todo-checked']" @click="todoList[i].done = !todoList[i].done">&nbsp;</span>
     <span class="todo-title" contenteditable="contenteditable" @blur="(e) => { todoList[i].title = e.target.textContent.trim(); }">{{todoList[i].title}}</span>
    </div>
    <span class="todo-button float-right" @click="todoList.splice(i, 1)">x</span>
   </li>
   <li class="clearfix"><input class="todo-editing" v-model="editing" @keyup.enter="add()" /> <span class="todo-button float-right" @click="add()">+</span></li>
  </ul>
 </div>
</div>`);

    //Below are controller for todo list
    var msgCtrl = new Vue({
        el: '#todoListView',
        data: {
            todoList: todoList,
            editing: "",
            isFromCache: false
        },
        computed: {
            sortedIndexes: function() {
                var indexes = [];
                this.todoList.forEach((x,i)=>indexes.push(i));
                indexes.sort((i, j)=> {
                    let [todoi, todoj] = [this.todoList[i], this.todoList[j]];
                    if (todoi.done === todoj.done) { return todoi.title < todoj.title ? -1 : 1; }
                    return todoi.done - todoj.done;
                });
                return indexes;
            },
            unDoneTodoCount: function() { return this.todoList.filter(x=>!x.done).length; },
            doneTodoCount: function() { return this.todoList.filter(x=>x.done).length; }
        },
        methods: {
            add: function() {
                if (this.editing.trim()!=='') {
                    this.todoList.push({title:this.editing, done: false});
                    this.editing='';
                }
            },
        },
        // When todo is changed (marked done/un-done, added, removed)
        // we save data to local storage
        watch: {
            todoList: {
                handler: function(val, oldval) {
                    if (this.isFromCache) { this.isFromCache = false; return; }
                    GM_setValue('todoList', val);
                    todoListVersion = new Date().getTime();
                    GM_setValue('todoList.version', todoListVersion);
                },
                deep: true
            }
        }
    });

    // Add a timer to check if todo is updated in another page
    var timer = setInterval(function() {
        var version = GM_getValue('todoList.version');
        if (version > todoListVersion) {
            todoListVersion = version;
            console.log('Found todoList changed');
            msgCtrl.isFromCache = true;
            msgCtrl.todoList = GM_getValue('todoList');
            console.log('todoList updated');
        }
    }, 1000);
})();